home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Original Shareware 1.1
/
The Original Shareware (WeMake CDs)(Volume 1.1)(CDs, Inc)(1993).iso
/
6
/
unix_cu.zip
/
CU.C
Wrap
Text File
|
1986-12-21
|
18KB
|
668 lines
/* WARNING - this program typed in by hand from DECUS source, so beware typos
such as extra/missing ;'s and what not. (/ \ | & =) */
/* Note - the first two arguments to "ioctl" reversed. */
#include <stdio.h>
#include <signal.h>
#include <sgtty.h>
#include <errno.h>
/*
* cu telno [-t] [-s speed] [-l line] [-a acu]
*
* -t is for dial-out to terminal.
* speeds are: 110, 134, 150, 300, 1200. 300 is default.
*
* Escape with `~' at beginning of line.
* Ordinary diversions are ~<, ~> and ~>>.
* Silent output diversions are ~>: and ~>>:.
* Terminate output diversion with ~> alone.
* Quit is ~. and ~! gives local command or shell.
* Also ~$ for canned procedure pumping remote.
* ~%put from [to] and ~%take from [to] invoke builtins
*/
#define CRLF "\r\n"
#define wrc(ds) write(ds,&c,1)
int errno;
int rd_pid, wt_pid;
int sig16cnt;
char *devcul = "/dev/cul0";
char *devcua = "/dev/cua0";
char *lspeed = "300";
int ln; /* fd for comm line */
char tkill, terase; /* current input kill & erase */
char c;
char *connmsg[] = {
"",
"line busy",
"call dropped",
"no carrier",
"can't fork",
"acu access",
"tty access",
"tty hung",
"usage: cu telno [-t] [-s speed] [-l line] [-a acu]"
};
char prompt[16], tk_tmplt[128], pt_tmplt[128];
int pipefd[2];
FILE *pipefp, *fdopen();
int intr;
int dout;
int nhup;
sig16()
{
signal(16, sig16);
sig16cnt++;
}
sig2()
{
signal(SIGINT, SIG_IGN);
intr = 1;
}
do_macro(string, f) /* processes system macros for take and put -cwg */
/* Note - Probably the better way to handle "escape" sequences
is to use something like "~" rather than "^" as a lead-in.
This would allow ^ to stand for caret (circumflex) itself,
~~ would represent tilde, with lowercase equivalents for the
specific functions below (e.g., ~v for sync and ~{ for EOF escape).
Then, ALL control characters could be represented as ~@ ~A ... ~^ ~_. */
char *string; /* pointer to the macro command string */
int f; /* fd of input file, used if this is ~%put */
{
int rcount;
int sync; /* whether we have to wait for prompt for ea out ln */
char *strptr; /* roving pointer into macro string */
strptr = string; /* begin at the beginning... */
sig16cnt = 0; /* make sure no prev syncs to mess up */
while (c = *(strptr++)) { /* while there is more to do... */
if (c != '~') { /* if just part of normal string... */
wrc(ln); /* send it out,... */
continue; /* and do next character */
}
if (!(c = *(strptr++))) /* if premature end of string... */
break; /* just ignore trailing '~' */
if (c == '~') { /* if "~~", send single ~ */
wrc(ln);
continue;
}
if (c == 'v') { /* if "~v" (SYN) - synchronize with */
while (!sig16cnt) /* rd() process on nxt prompt */
sleep(2);
sig16cnt = 0; /* reset for next sync */
continue;
}
if (c == '{') { /* if "~{" (ESC) - divert rd() proc */
kill(rd_pid, 16); /* send signal 16 to rd()
process to read pipe and divert read */
strptr += 2; /* skip over this token */
while (*(strptr - 2) != '~' && *(strptr - 1) != '}')
strptr++; /* skip to end of EOF */
continue;
}
if (c == 'l') { /* if "~l" - send lines of in fl */
strptr++; /* skip following "~" (we trust) */
if ((c = *(strptr++)) == 'v') /* if we must sync */
sync = 1; /* with incoming prompts */
else
sync = 0;
/*/*/
intr = 0;
if (!nhup)
signal(SIGINT, sig2);
mode(2); /* no raw (catch interrupt) */
rcount = 0;
while(!intr && rdc(f) == 1) {
rcount++; /* copy file to line */
if (c == tkill || c == terase)
wrln("\\"); /* write string to ln */
if (wrc(ln) != 1) {
xsleep(2);
if (wrc(ln) != 1) { /* write c to ln */
prf("character missed");
intr = 1;
break;
}
}
if ((c == '\n') && sync) { /* if we must wait */
while (!sig16cnt) /* for prompt */
sleep(1);
sig16cnt = 0; /* next time */
}
}
signal(SIGINT, SIG_IGN);
close(f);
if (intr) {
wrln("\n");
prf("stopped after %d bytes", rcount);
}
mode(1); /* raw (do not catch interrupt) */
/*/*/
continue;
}
if (c > '/' && c < ':') { /* delay spec. 0 - 9 sec's */
sleep(c - '0'); /* calculate binary integer interval */
continue;
}
if (c == '?') { /* "~?" (DEL) - send DEL character */
c = '\177'; /* construct a DEL character */
wrc(ln);
continue;
}
/* other control characters - interpret and send them. */
if (c > '?' && c < '`') { /* if legitimate control ch */
c -= '@'; /* adjust to the control character */
wrc(ln); /* and send it out. */
continue;
}
} /* end of while loop */
}
rdc(ds) {
ds = read(ds, &c, 1);
c &= 0177;
return(ds);
}
int set14;
xsleep(n)
{
xalarm(n);
pause();
xalarm(0);
}
xalarm(n)
{
set14 = n;
alarm(n);
}
sig14()
{
signal(SIGALRM, sig14);
if (set14) alarm(1); /* Set alarm to go off in one second. */
}
/*
* main: get connection, set speed for line.
* spawn child to invoke rd to read from line, output to fd 1 (stdout).
* main line invokes wr to read tty, write to line.
*/
main(ac, av)
char *av[];
{
static char *sysdesfl = "/etc/unix.cs";
/* system description filename string */
FILE *sdf; /* pointer to system description file */
int fk;
int speed;
char *telno;
struct sgttyb stbuf;
if (pipe(pipefd)) /* if cannot construct pipe */
puts("Cannot construct pipe.");
signal(16, sig16);
sig16cnt = 0;
signal(SIGALRM, sig14);
if (ac < 2) { /* must at least have telno arg */
prf(connmsg[8]); /* usage message */
exit(8);
}
telno = av[1];
av += 2;
ac -= 2;
for (; ac > 0; av++) {
if (equal(*av, "-t")) { /* dialout to terminal (direct?) */
dout = 1;
--ac;
continue;
}
if (ac < 2) /* just one remaining argument is meaningless */
break;
if (equal(*av, "-s")) /* speed (baud rate) */
lspeed = *++av;
else if (equal(*av, "-l")) /* comm line override */
devcul = *++av;
else if (equal(*av, "-a")) /* ACU override */
devcua = *++av;
else if (equal(*av, "-d")) /* system description file */
sysdesfl = *++av;
else
break;
ac -= 2;
}
if ((sdf = fopen(sysdesfl, "r")) == NULL)
printf("Cannot open system description file \"%s\".", sysdesfl);
fgets(prompt, 16, sdf); /* read the system prompt string */
prompt[strlen(prompt) - 1] = '\0';
fgets(pt_tmplt, 128, sdf); /* get the ~%put template string */
pt_tmplt[strlen(pt_tmplt) - 1] = '\0';
fgets(tk_tmplt, 128, sdf); /* get the ~%take template string */
tk_tmplt[strlen(tk_tmplt) - 1] = '\0';
fclose(sdf);
if (!exists(devcua) || !exists(devcul))
exit(9);
ln = conn(devcul, devcua, telno); /* make the connection */
if (ln < 0) {
prf("Connect failed: %s", connmsg[-ln]);
exit(-ln);
}
switch (atoi(lspeed)) {
case 110:
speed = B110; break;
case 150:
speed = B150; break;
default:
case 300:
speed = B300; break;
case 1200:
speed = B1200; break;
}
stbuf.sg_ispeed = speed;
stbuf.sg_ospeed = speed;
stbuf.sg_flags = EVENP|ODDP;
if (!dout) /* if not dialout to terminal */
stbuf.sg_flags |= RAW;
ioctl(ln, TIOCSETP, &stbuf); /* set parameters */
ioctl(ln, TIOCEXCL, (struct sgttyb *) NULL); /* exclusive use mode */
ioctl(ln, TIOCHPCL, (struct sgttyb *) NULL); /* hangup on close */
prf("Connected");
wt_pid = getpid(); /* make note of write process id */
if (dout) /* if dialout to terminal */
fk = -1;
else
fk = fork();
rd_pid = fk; /* make note of read process ID */
nhup = (int) signal(SIGINT, SIG_IGN);
if (fk == 0) { /* if this is the child of above fork */
rd(); /* read from this line */
prf("/007Lost carrier");
exit(3);
}
mode(1);
wr(); /* this is parent process - write to line */
mode(0);
kill(fk, SIGKILL); /* done - kill child reader */
wait((int *) NULL); /* wait for it to die */
stbuf.sg_ispeed = 0;
stbuf.sg_ospeed = 0;
ioctl(ln, TIOCSETP, &stbuf); /* set parameters */
prf("Disconnected");
exit(0);
}
/*
* conn: establish dial-out connection.
* Example: fd = conn("/dev/ttyh", "/dev/dn1", "4500");
* Returns descriptor open to tty for reading and writing.
* Negative values (-1 ... -7) denote errors in connmsg.
* Uses alarm and fork/wait; requires sig14 handler.
* Be sure to disconnect tty when done, via HUPCL or stty 0.
*/
conn(dev, acu, telno)
char *dev, *acu, *telno;
{
struct sgttyb stbuf;
extern errno;
char *p, *q, b[30];
int er, fk, dn, dh, t;
er = 0;
fk = (-1);
if ((dn = open(acu, 1)) < 0) {
er = (errno == 6 ? 1 : 5); /* "line busy" or "acu access"*/
goto X;
}
if ((fk = fork()) == (-1)) { /* if couldn't spawn child process */
er = 4; /* "can't fork" */
goto X;
}
if (fk == 0) { /* if this is child process */
open (dev, 2); /* open line for read and write */
for (;;) pause();
}
xsleep(2);
/*
* copy phone #, assure EON
*/
p = b;
q = telno;
while (*p++ = (*q++))
; /* copy telno string to b[] */
p--;
if (*(p - 1) != '<') { /* "<" is end-of-number */
if (*(p - 1) != '-') *p++ = '-'; /* "-" await dialtone */
*p++ = '<';
}
t = p - b; /* get length of string */
xalarm(5 * t); /* set watchdog timer */
t = write(dn, b, t); /* write telno to ACU */
xalarm(0);
if (t < 0) {
er = 2; /* "call dropped" */
goto X;
}
/* close(dn) */
xalarm(40); /* was 5; sometimes missed carrier */
dh = open(dev, 2); /* open line for read/write */
xalarm(0);
if (dh < 0) {
er = (errno == 4 ? 3 : 6); /* "no carrier"or"tty access" */
goto X;
}
/* ?!? ioctl(TIOCGETP, ln, &stbuf); /* get parameters */
ioctl(dh, TIOCGETP, &stbuf);
stbuf.sg_flags &= ~ECHO;
xalarm(10);
ioctl(dh, TIOCSETP, &stbuf); /* set parameters */
ioctl(dh, TIOCHPCL, (struct sgttyb *) NULL); /* hangup on close */
xalarm(0);
X:
if (er) close(dn);
if (fk != (-1)) { /* if there is a child process */
kill (fk, SIGKILL);
xalarm(10);
while ((t = wait((int *) NULL)) != (-1) && t != fk)
; /* wait for child to die */
xalarm(0);
}
return (er ? -er : dh);
}
/*
* wr: write to remote: 0 -> line (0 = stdin)
* ~. terminate
* ~<file send file
* ~! local login-style shell
* ~!cmd execute cmd locally
* ~$proc execute proc locally, send output to line
* ~%cmd execute builtin cmd (put and take)
*/
wr()
{
int ds, fk, lcl, x;
char *p, b[600];
pipefp = fdopen(pipefd[1], "w"); /* open write strm into pipe */
for (;;) {
p = b;
while (rdc(0) == 1 || (errno == EINTR && rdc(0) == 1)) {
/* reads into c from stdin */
if (p == b) lcl = (c == '~'); /* line "~..." local */
if (p == b + 1 && b[0] == '~') lcl = (c != '~');
/* ...unless starts with "~~..." */
if (c == 0) c = 0177; /* map NUL to DEL */
if (!lcl) {
if (wrc(ln) == 0) { /* write char to line */
prf("line gone"); return;
}
}
if (lcl) {
if (c == 0177) c = tkill; /* line kill */
if (c == '\r' || c == '\n') goto A;
/* break out of transmit loop */
if (!dout) wrc(0);
/* if not dialout, echo char to stdin */
}
*p++ = c;
if (c == terase) { /* if erase character */
p = p - 2; /* back up one space */
if (p < b) p = b;
}
if (c == tkill || c == 0177 || c == '\r' || c == '\n')
p = b; /* reuse line */
}
return;
A:
if (!dout) echo("");
*p = 0;
switch (b[1]) {
case '.':
case '\004': /* ^D is EOF */
return; /* finished with call */
case '!': /* escape to shell */
case '$': /* transmit stdout of foll. cmd */
fk = fork();
if (fk == 0) { /* if this is child... */
close(1);
dup(b[1] == '$' ? ln : 2);
close(ln);
mode(0);
if (!nhup) signal(SIGINT, SIG_DFL);
if (b[2] == 0) execl("/bin/sh", "-", 0);
else execl("/bin/sh", "sh", "-c", b + 2, 0);
prf("Can't execute shell");
exit(~0);
}
if (fk != (-1)) {
while (wait(&x) != fk)
;
}
mode(1);
if (b[1] == '!') echo("!");
else {
if (dout) echo("$");
}
break;
case '<': /* read file out the line */
if (b[2] == 0) break;
if ((ds = open(b + 2, 0)) < 0) {
prf("Can't divert %s", b + 1);
break;
}
intr = x = 0;
mode(2);
if (!nhup) signal(SIGINT, sig2);
while (!intr && rdc(ds) == 1) {
if (wrc(ln) == 0) {
x = 1;
break;
}
}
signal(SIGINT, SIG_IGN);
close(ds);
mode(1);
if (x) return;
if (dout) echo("<");
break;
case '%': /* put and take commands */
dopercen(&b[2]);
break;
default:
prf("Use `~~' to start line with `~'");
}
continue;
}
}
dopercen(line)
register char *line;
{
char cmd_line[256];
char *args[10];
register narg, f;
for (narg = 0; narg < 10;) { /* collect arguments */
while (*line == ' ' || *line == '\t')
line++; /* scan past white space */
if (*line == '\0')
break;
args[narg++] = line; /* there is an argument here */
while (*line != '\0' && *line != ' ' && *line != '\t')
line++; /* find end of argument */
if (*line == '\0')
break;
*line++ = '\0'; /* terminate argument string */
}
if (equal(args[0], "take")) {
if (narg < 2) {
prf("usage: ~%%take from [to]");
return;
}
if (narg < 3)
args[2] = args[1];
fprintf(pipefp, "~>:%s\n", args[2]); /* put filnam in pipe */
fflush(pipefp); /* and make sure rd() sees it */
sprintf(cmd_line, tk_tmplt, args[1], args[1], args[1], args[1]);
/* substitute "from" filname for all "%s" in template */
do_macro(cmd_line, f); /* process ~%take command mac */
return;
}
else if (equal(args[0], "put")) {
if (narg < 2) {
prf("usage: ~%%put from [to]");
return;
}
if (narg < 3)
args[2] = args[1];
if ((f = open(args[1], 0)) < 0) { /* open "from" file */
prf("cannot open: %s", args[1]); /* for read */
return;
}
sprintf(cmd_line, pt_tmplt, args[2], args[2], args[2], args[2]);
/* substitute "to" filename for all "%s" in template */
do_macro(cmd_line, f); /* process ~%put macro string */
return;
}
prf("~%%%s unknown\n", args[0]);
}
equal(s1, s2)
register char *s1, *s2;
{
while (*s1++ == *s2)
if (*s2++ == '\0')
return(1);
return(0);
}
wrln(s)
register char *s;
{
while (*s)
write(ln, s++, 1);
}
/*
* rd: read from remote: line -> 1 (1 = stdout).
* catch:
* ~>[>][:][file]
* stuff from file...
* ~> (ends diversion)
*/
rd()
{
int ds, slnt;
char *p, *q, b[600];
char eofstr[32]; /* array of EOF identifier character string */
int i, j; /* indices used to pick out EOF string */
pipefp = fdopen(pipefd[0], "r"); /* open pipe end for reading */
for (i = 2; (tk_tmplt[i - 2] != '~') && (tk_tmplt[i - 1] != '{'); i++)
; /* find start of EOF definition string */
for (j = i; (tk_tmplt[j] != '~') && (tk_tmplt[j + 1] != '}'); j++)
; /* find end of EOF definition string */
strncpy(eofstr, tk_tmplt + i, j - i); /* copy EOF string from tmplt */
eofstr[j - i] = '\0'; /* terminate the EOF string */
p = b;
ds = (-1);
while (rdc(ln) == 1 || (errno == EINTR && rdc(ln) == 1)) {
/* for each character... */
if (ds < 0) slnt = 0;
if (!slnt) wrc(1); /* if not silent, write to stdout */
*p++ = c;
*p = '\0'; /* make sure legitimate string */
if (!strcmp(prompt, b)) /* if this looks like a prompt... */
kill (wt_pid, 16); /* send signal 16 to wr() */
if (c != '\n') continue;
/*** Complete lines ***/
q = p;
p = b; /* if newline, reset line */
if (*(q - 2) == '\r') { /* get rid of CR, if there */
q--;
*(q - 1) = (*q);
}
if (ds >= 0) { /* if we are currently redirecting input... */
if (strncmp(eofstr, b, strlen(eofstr))){/* if not EOF */
write(ds, b, q - b); /* write ths ln to fl */
continue; /* gt nxt lin */
}
/*** Hit EOF ***/
close(ds);
ds = (-1); /* remember that we are not redirectn */
write(1, b, q - b); /* might as well echo EOF ln. */
/* write(1, CRLF, sizeof(CRLF)); /* seems too much */
write(1, "\r", 1);
slnt = 0;
}
else { /* we are not redirecting now - see if we should start*/
if (!sig16cnt) /* if we have not received signal to */
continue; /* read pipe & redirect, done */
sig16cnt = 0; /* reset for next time around */
/*** Start redirection ***/
fgets(b, 64, pipefp); /* get local command */
b[strlen(b) - 1] = '\0'; /* end string w/o \n */
slnt = 0;
q = b + 2;
if (*q == '>') q++;
if (*q == ':') {
slnt = 1;
q++;
}
if (*q == 0) {
ds = (-1);
continue;
}
if (b[2] != '>' || (ds = open(q, 1)) < 0)
ds = creat(q, 0644);
lseek(ds, (long) 0, 2);
if (ds < 0)
prf("Can't divert %s", b + 1);
}
}
perror("read perror");
}
struct {char lobyte; char hibyte; }; /* sic - but why??? */
mode(f)
{
struct sgttyb stbuf;
if (dout) return;
ioctl(0, TIOCGETP, &stbuf); /* Get parameters */
tkill = stbuf.sg_kill;
terase = stbuf.sg_erase;
if (f == 0) {
stbuf.sg_flags &= ~RAW;
stbuf.sg_flags |= ECHO | CRMOD;
}
if (f == 1) {
stbuf.sg_flags |= RAW;
/* stbuf.sg_flags &= ECHO | CRMOD; /* sic, but isn't it wrong? */
stbuf.sg_flags &= ~(ECHO | CRMOD);
}
if (f == 2) {
stbuf.sg_flags &= ~RAW;
stbuf.sg_flags &= ~(ECHO | CRMOD);
}
ioctl(0, TIOCSETP, &stbuf); /* set parameters */
}
echo(s)
char *s;
{
char *p;
for (p = s; *p; p++)
;
if (p > s) write(0, s, p - s);
write(0, CRLF, sizeof(CRLF));
}
prf(f, s)
char *f;
char *s;
{
fprintf(stderr, f, s);
fprintf(stderr, CRLF);
}
exists(devname)
char *devname;
{
if (access(devname, 0) == 0)
return(1);
prf("%s does not exist", devname);
return(0);
}